home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / database / hl / hl-1.000 / hl-1 / TkInterface / TkvBTree.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-21  |  21.2 KB  |  853 lines

  1. /*
  2.  * ------------------------------------------------------------------
  3.  * Home Libarian 1.0B by Deepwoods Software
  4.  * ------------------------------------------------------------------
  5.  * TkvBTree.cc - Tcl/Tk Interface for the vBTree class
  6.  * Created by Robert Heller on Mon Apr 17 14:03:20 1995
  7.  * ------------------------------------------------------------------
  8.  * Modification History: 
  9.  * ------------------------------------------------------------------
  10.  * Contents:
  11.  * ------------------------------------------------------------------
  12.  *  
  13.  *     Home Librarian Database -- a program for maintaining a database
  14.  *                                for a home library
  15.  *     Copyright (C) 1991-1995  Robert Heller D/B/A Deepwoods Software
  16.  *             51 Locke Hill Road
  17.  *             Wendell, MA 01379-9728
  18.  * 
  19.  *     This program is free software; you can redistribute it and/or modify
  20.  *     it under the terms of the GNU General Public License as published by
  21.  *     the Free Software Foundation; either version 2 of the License, or
  22.  *     (at your option) any later version.
  23.  * 
  24.  *     This program is distributed in the hope that it will be useful,
  25.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *     GNU General Public License for more details.
  28.  * 
  29.  *     You should have received a copy of the GNU General Public License
  30.  *     along with this program; if not, write to the Free Software
  31.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  32.  * 
  33.  *  
  34.  */
  35.  
  36. #include <TkvBTree.h>
  37. #include <TkCardRecord.h>
  38. #include <ListRecord.h>
  39.  
  40. void_pt TkvBTree::Handles = NULL;
  41.  
  42. TkvBTree::TkvBTree(char *filename,OpenMode mode,int nfree)
  43. {
  44.     (void) Tree.open(filename,mode,nfree);
  45.     FileName = filename;
  46.     _mode = (OpenMode) (mode & ModeMask);
  47. }
  48.  
  49. TkvBTree::~TkvBTree()
  50. {
  51. }
  52.  
  53. static Key subjkey;
  54. static Tcl_Interp *subjinterp = NULL;
  55.  
  56. static void ExamineSubj(CoreItem* item,int level)
  57. {
  58.     if (subjinterp == NULL) return;
  59.     if (item->data.size <= 0) return;
  60.     ListRecord rec(&item->data);
  61.     int icount = rec.ElementCount();
  62.     for (int i = 0; i < icount; i++) {
  63.         if (strcasecmp(subjkey,rec[i]) == 0) {
  64.             Tcl_AppendElement(subjinterp,item->key);
  65.             return;
  66.         }
  67.     }
  68. }
  69.  
  70. int TkvBTree::TclFunction(Tcl_Interp *interp,int argc, char *argv[])
  71. {
  72.     static char **newelements = NULL;
  73.     static int numnewelements = 0;
  74.     if (argc == 1)
  75.     {
  76.         // no option, echo slots
  77.         Tcl_DString result;
  78.         Tcl_DStringInit(&result);
  79.         Tcl_DStringAppendElement(&result,"vBTree");
  80.  
  81.         Tcl_DStringStartSublist(&result);
  82.         Tcl_DStringAppendElement(&result,"FileName");
  83.         Tcl_DStringAppendElement(&result,(char*)FileName);
  84.         Tcl_DStringEndSublist(&result);
  85.  
  86.         Tcl_DStringStartSublist(&result);
  87.         Tcl_DStringAppendElement(&result,"Mode");
  88.         switch (_mode)
  89.         {
  90.             case ReadOnly: Tcl_DStringAppendElement(&result,"ReadOnly");
  91.                        break;
  92.             case ReadWrite: Tcl_DStringAppendElement(&result,"ReadWrite");
  93.                        break;
  94.         }
  95.         Tcl_DStringEndSublist(&result);            
  96.  
  97.         Tcl_DStringStartSublist(&result);
  98.         Tcl_DStringAppendElement(&result,"OpenStat");
  99.         switch (Tree.OpenStat())
  100.         {
  101.             case failure: Tcl_DStringAppendElement(&result,"failure");
  102.                       break;
  103.             case openold: Tcl_DStringAppendElement(&result,"openold");
  104.                       break;
  105.             case opennew: Tcl_DStringAppendElement(&result,"opennew");
  106.                       break;
  107.         }
  108.         Tcl_DStringEndSublist(&result);
  109.  
  110.         Tcl_DStringResult(interp,&result);
  111.         return TCL_OK;
  112.     }
  113.     if (argc < 2)
  114.     {
  115.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  116.                  argv[0], " option ?arg arg ...?\"",
  117.                  (char *) NULL);
  118.         return TCL_ERROR;
  119.     }
  120.     if (strcmp(argv[1], "type") == 0)
  121.     {
  122.         if (argc != 2)
  123.         {
  124.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  125.                      argv[0]," ",argv[1],(char *) NULL);
  126.             return TCL_ERROR;
  127.         }
  128.         Tcl_AppendResult(interp, "vBTree", (char *) NULL);
  129.         return TCL_OK;
  130.     } else if (strcmp(argv[1], "openstat") == 0)
  131.     {
  132.         if (argc != 2)
  133.         {
  134.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  135.                      argv[0]," ",argv[1],"\"",
  136.                      (char *) NULL);
  137.             return TCL_ERROR;
  138.         }
  139.         switch (Tree.OpenStat())
  140.         {
  141.             case failure: Tcl_AppendElement(interp, "failure"); break;
  142.             case openold: Tcl_AppendElement(interp, "openold"); break;
  143.             case opennew: Tcl_AppendElement(interp, "opennew"); break;
  144.         }
  145.         return TCL_OK;
  146.     } else if (strcmp(argv[1], "mode") == 0)
  147.     {
  148.         if (argc != 2)
  149.         {
  150.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  151.                      argv[0]," ",argv[1],"\"",
  152.                      (char *) NULL);
  153.             return TCL_ERROR;
  154.         }
  155.         switch (_mode)
  156.         {
  157.             case ReadOnly: Tcl_AppendElement(interp, "ReadOnly"); break;
  158.             case ReadWrite:Tcl_AppendElement(interp, "ReadWrite"); break;
  159.         }
  160.         return TCL_OK;
  161.     } else if (strcmp(argv[1], "filename") == 0)
  162.     {
  163.         if (argc != 2)
  164.         {
  165.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  166.                      argv[0]," ",argv[1],"\"",
  167.                      (char *) NULL);
  168.             return TCL_ERROR;
  169.         }
  170.         Tcl_AppendElement(interp,(char*)FileName);
  171.         return TCL_OK;
  172.     } else if (strcmp(argv[1], "searchids") == 0)
  173.     {
  174.         Key searchkey;
  175.         if (argc == 2) searchkey[0] = '\0';
  176.         else if (argc == 3)
  177.         {
  178.             strncpy(searchkey,argv[2],KeySize-1);
  179.             searchkey[KeySize-1] = '\0';
  180.         } else
  181.         {
  182.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  183.                      argv[0]," ",argv[1]," ?key?\"",
  184.                      (char *) NULL);
  185.             return TCL_ERROR;
  186.         }
  187.         CoreItem item;
  188.         if (Tree.SearchId(searchkey,&item))
  189.         {
  190.             do {
  191.                 Tcl_AppendElement(interp,(char*)item.key);
  192.             } while (Tree.SearchIdAgain(&item));
  193.         }
  194.         return TCL_OK;
  195.     } else if (strcmp(argv[1], "readid") == 0)
  196.     {
  197.         Key searchkey;
  198.         if (argc != 3)
  199.         {
  200.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  201.                      argv[0]," ",argv[1]," key\"",
  202.                      (char *) NULL);
  203.             return TCL_ERROR;
  204.         }
  205.         CoreItem item;
  206.         strncpy(searchkey,argv[2],KeySize-1);
  207.         searchkey[KeySize-1] = '\0';
  208.         if (Tree.SearchId(searchkey,&item) &&
  209.             strlen(searchkey) == strlen(item.key))
  210.         {
  211.             return createTkCardRecord(interp,&item);
  212.         } else
  213.         {
  214.             return TCL_OK;
  215.         }
  216.     } else if (strcmp(argv[1], "searchtitles") == 0)
  217.     {
  218.         Key searchkey;
  219.         if (argc == 2) searchkey[0] = '\0';
  220.         else if (argc == 3)
  221.         {
  222.             strncpy(searchkey,argv[2],KeySize-1);
  223.             searchkey[KeySize-1] = '\0';
  224.         } else
  225.         {
  226.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  227.                      argv[0]," ",argv[1]," ?key?\"",
  228.                      (char *) NULL);
  229.             return TCL_ERROR;
  230.         }
  231.         CoreItem item;
  232.         if (Tree.SearchTitle(searchkey,&item))
  233.         {
  234.             do {
  235.                 Tcl_AppendElement(interp,(char*)item.key);
  236.             } while (Tree.SearchTitleAgain(&item));
  237.         }
  238.         return TCL_OK;
  239.     } else if (strcmp(argv[1], "readtitlelist") == 0)
  240.     {
  241.         Key searchkey;
  242.         if (argc != 3)
  243.         {
  244.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  245.                      argv[0]," ",argv[1]," key\"",
  246.                      (char *) NULL);
  247.             return TCL_ERROR;
  248.         }
  249.         CoreItem item;
  250.         strncpy(searchkey,argv[2],KeySize-1);
  251.         searchkey[KeySize-1] = '\0';
  252.         if (Tree.SearchTitle(searchkey,&item) &&
  253.             strlen(searchkey) == strlen(item.key))
  254.         {
  255.             ListRecord rec(&item.data);
  256.             int elc = rec.ElementCount();
  257.             for (int i = 0;i < elc;i++)
  258.             {
  259.                 Tcl_AppendElement(interp,rec[i]);
  260.             }
  261.             return  TCL_OK;
  262.         } else
  263.         {
  264.             return TCL_OK;
  265.         }
  266.     } else if (strcmp(argv[1], "searchauthors") == 0)
  267.     {
  268.         Key searchkey;
  269.         if (argc == 2) searchkey[0] = '\0';
  270.         else if (argc == 3)
  271.         {
  272.             strncpy(searchkey,argv[2],KeySize-1);
  273.             searchkey[KeySize-1] = '\0';
  274.         } else
  275.         {
  276.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  277.                      argv[0]," ",argv[1]," ?key?\"",
  278.                      (char *) NULL);
  279.             return TCL_ERROR;
  280.         }
  281.         CoreItem item;
  282.         if (Tree.SearchAuthor(searchkey,&item))
  283.         {
  284.             do {
  285.                 Tcl_AppendElement(interp,(char*)item.key);
  286.             } while (Tree.SearchAuthorAgain(&item));
  287.         }
  288.         return TCL_OK;
  289.     } else if (strcmp(argv[1], "readauthorlist") == 0)
  290.     {
  291.         Key searchkey;
  292.         if (argc != 3)
  293.         {
  294.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  295.                      argv[0]," ",argv[1]," key\"",
  296.                      (char *) NULL);
  297.             return TCL_ERROR;
  298.         }
  299.         CoreItem item;
  300.         strncpy(searchkey,argv[2],KeySize-1);
  301.         searchkey[KeySize-1] = '\0';
  302.         if (Tree.SearchAuthor(searchkey,&item) &&
  303.             strlen(searchkey) == strlen(item.key))
  304.         {
  305.             ListRecord rec(&item.data);
  306.             int elc = rec.ElementCount();
  307.             for (int i = 0;i < elc;i++)
  308.             {
  309.                 Tcl_AppendElement(interp,rec[i]);
  310.             }
  311.             return  TCL_OK;
  312.         } else
  313.         {
  314.             return TCL_OK;
  315.         }
  316.     } else if (strcmp(argv[1], "searchsubjects") == 0)
  317.     {
  318.         Key searchkey;
  319.         if (argc == 2) searchkey[0] = '\0';
  320.         else if (argc == 3)
  321.         {
  322.             strncpy(searchkey,argv[2],KeySize-1);
  323.             searchkey[KeySize-1] = '\0';
  324.         } else
  325.         {
  326.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  327.                      argv[0]," ",argv[1]," ?key?\"",
  328.                      (char *) NULL);
  329.             return TCL_ERROR;
  330.         }
  331.         CoreItem item;
  332.         if (Tree.SearchSubj(searchkey,&item))
  333.         {
  334.             do {
  335.                 Tcl_AppendElement(interp,(char*)item.key);
  336.             } while (Tree.SearchSubjAgain(&item));
  337.         }
  338.         return TCL_OK;
  339.     } else if (strcmp(argv[1], "readsubjectlist") == 0)
  340.     {
  341.         Key searchkey;
  342.         if (argc != 3)
  343.         {
  344.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  345.                      argv[0]," ",argv[1]," key\"",
  346.                      (char *) NULL);
  347.             return TCL_ERROR;
  348.         }
  349.         CoreItem item;
  350.         strncpy(searchkey,argv[2],KeySize-1);
  351.         searchkey[KeySize-1] = '\0';
  352.         if (Tree.SearchSubj(searchkey,&item) &&
  353.             strlen(searchkey) == strlen(item.key))
  354.         {
  355.             ListRecord rec(&item.data);
  356.             int elc = rec.ElementCount();
  357.             for (int i = 0;i < elc;i++)
  358.             {
  359.                 Tcl_AppendElement(interp,rec[i]);
  360.             }
  361.             return  TCL_OK;
  362.         } else
  363.         {
  364.             return TCL_OK;
  365.         }
  366.     } else if (strcmp(argv[1], "fetchsubjs") == 0)
  367.     {
  368.         if (argc != 3)
  369.         {
  370.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  371.                      argv[0]," ",argv[1]," idkey\"",
  372.                      (char *) NULL);
  373.             return TCL_ERROR;
  374.         }
  375.         strncpy(subjkey,argv[2],KeySize-1);
  376.         subjkey[KeySize-1] = '\0';
  377.         subjinterp = interp;
  378.         Tree.TraverseSubj(ExamineSubj);
  379.         subjinterp = NULL;
  380.         return TCL_OK;
  381.     } else if (strcmp(argv[1], "updatesubjs") == 0)
  382.     {
  383.         Key key;
  384.         int subjc,osubjc,is1,is2;
  385.         char **subjv,**osubjv;
  386.  
  387.         if (_mode != ReadWrite)
  388.         {
  389.             Tcl_AppendResult(interp, "ReadOnly file!",(char *) NULL);
  390.             return TCL_ERROR;
  391.         }
  392.         if (argc != 5)
  393.         {
  394.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  395.                      argv[0]," ",argv[1],
  396.                      " subjs osubjs idkey\"",
  397.                      (char *) NULL);
  398.             return TCL_ERROR;
  399.         }
  400.         strncpy(key,argv[4],KeySize-1);
  401.         key[KeySize-1] = '\0';
  402.         if (Tcl_SplitList(interp, argv[2], &subjc, &subjv) != TCL_OK)
  403.             return TCL_ERROR;
  404.         if (Tcl_SplitList(interp, argv[3], &osubjc, &osubjv) != TCL_OK)
  405.             return TCL_ERROR;
  406.         for (is1 = 0; is1 < osubjc;is1++)
  407.         {
  408.             Boolean retain = false;
  409.             for (is2 = 0; is2 < subjc;is2++)
  410.             {
  411.                 if (strncasecmp(osubjv[is1],
  412.                         subjv[is2],
  413.                         KeySize-1) == 0)
  414.                 {
  415.                     retain = true;
  416.                     break;
  417.                 }
  418.             }
  419.             if (!retain)
  420.             {
  421.                 CoreItem temp;
  422.                 Key skey;
  423.                 strncpy(skey,osubjv[is1],KeySize-1);
  424.                 skey[KeySize-1] = '\0';
  425.                 if (Tree.SearchSubj(skey,&temp) &&
  426.                     strlen(skey) == strlen(temp.key))
  427.                 {
  428.                     ListRecord rec(&temp.data);
  429.                     int nitems = rec.ElementCount();
  430.                     int outitems = 0;
  431.                     if (nitems > numnewelements)
  432.                     {
  433.                         if (newelements != NULL)
  434.                             delete newelements;
  435.                         int numnewelements = (nitems+511) & ~(0x03ffL);
  436.                         newelements = new char*[numnewelements];
  437.                     }
  438.                     for (int i = 0; i < nitems; i++)
  439.                     {
  440.                         if (strcasecmp(rec[i],key) != 0)
  441.                         {
  442.                             newelements[outitems++] = rec[i];
  443.                         }
  444.                     }
  445.                     if (outitems == 0)
  446.                     {
  447.                         Tree.DeleteSubj(skey);
  448.                     } else
  449.                     {
  450.                         ListRecord newrec(outitems,newelements);
  451.                         Record rawrec = newrec;
  452.                         Tree.InsertSubj(skey,&rawrec);
  453.                     }
  454.                 }
  455.             }
  456.         }
  457.         for (is1 = 0; is1 < subjc;is1++)
  458.         {
  459.             Boolean addnew = true;
  460.             for (is2 = 0; is2 < osubjc;is2++)
  461.             {
  462.                 if (strncasecmp(subjv[is1],
  463.                         osubjv[is2],
  464.                         KeySize-1) == 0)
  465.                 {
  466.                     addnew = false;
  467.                     break;
  468.                 }
  469.             }
  470.             if (addnew)
  471.             {
  472.                 CoreItem temp;
  473.                 Key skey;
  474.                 strncpy(skey,subjv[is1],KeySize-1);
  475.                 skey[KeySize-1] = '\0';
  476.                 if (Tree.SearchSubj(skey,&temp) &&
  477.                     strlen(skey) == strlen(temp.key))
  478.                 {
  479.                     ListRecord rec(&temp.data);
  480.                     int nitems = rec.ElementCount();
  481.                     int outitems = 0;
  482.                     if ((nitems+1) > numnewelements)
  483.                     {
  484.                         if (newelements != NULL)
  485.                             delete newelements;
  486.                         int numnewelements = (nitems+512) & ~(0x03ffL);
  487.                         newelements = new char*[numnewelements];
  488.                     }
  489.                     for (int i = 0; i < nitems; i++)
  490.                     {
  491.                         if (strcasecmp(rec[i],key) != 0)
  492.                         {
  493.                             newelements[outitems++] = rec[i];
  494.                         }
  495.                     }
  496.                     newelements[outitems++] = (char*)key;
  497.                     ListRecord newrec(outitems,newelements);
  498.                     Record rawrec = newrec;
  499.                     Tree.InsertSubj(skey,&rawrec);
  500.                 } else
  501.                 {
  502.                     if (1 > numnewelements)
  503.                     {
  504.                         if (newelements != NULL)
  505.                             delete newelements;
  506.                         int numnewelements = 512;
  507.                         newelements = new char*[numnewelements];
  508.                     }
  509.                     newelements[0] = (char*)key;
  510.                     ListRecord newrec(1,newelements);
  511.                     Record rawrec = newrec;
  512.                     Tree.InsertSubj(skey,&rawrec);
  513.                 }
  514.             }
  515.         }
  516.         return TCL_OK;
  517.     } else if (strcmp(argv[1], "updateauthor") == 0)
  518.     {
  519.         Key key, authkey, oauthkey;
  520.         if (_mode != ReadWrite)
  521.         {
  522.             Tcl_AppendResult(interp, "ReadOnly file!",(char *) NULL);
  523.             return TCL_ERROR;
  524.         }
  525.         if (argc != 5)
  526.         {
  527.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  528.                      argv[0]," ",argv[1],
  529.                      " newauthor oldauthor idkey\"",
  530.                      (char *) NULL);
  531.             return TCL_ERROR;
  532.         }
  533.         strncpy(authkey,argv[2],KeySize-1);
  534.         authkey[KeySize-1] = '\0';
  535.         strncpy(oauthkey,argv[3],KeySize-1);
  536.         oauthkey[KeySize-1] = '\0';
  537.         strncpy(key,argv[4],KeySize-1);
  538.         key[KeySize-1] = '\0';
  539.         if (strcasecmp(authkey,oauthkey) != 0)
  540.         {
  541.             CoreItem temp;
  542.             if (Tree.SearchAuthor(oauthkey,&temp) &&
  543.                 strlen(oauthkey) == strlen(temp.key))
  544.             {
  545.                 ListRecord rec(&temp.data);
  546.                 int nitems = rec.ElementCount();
  547.                 int outitems = 0;
  548.                 if (nitems > numnewelements)
  549.                 {
  550.                     if (newelements != NULL)
  551.                             delete newelements;
  552.                         int numnewelements = (nitems+511) & ~(0x03ffL);
  553.                         newelements = new char*[numnewelements];
  554.                 }
  555.                 for (int i = 0; i < nitems; i++)
  556.                 {
  557.                     if (strcasecmp(rec[i],key) != 0)
  558.                     {
  559.                         newelements[outitems++] = rec[i];
  560.                     }
  561.                 }
  562.                 if (outitems == 0)
  563.                 {
  564.                     Tree.DeleteAuthor(oauthkey);
  565.                 } else
  566.                 {
  567.                     ListRecord newrec(outitems,newelements);
  568.                     Record rawrec = newrec;
  569.                     Tree.InsertAuthor(oauthkey,&rawrec);
  570.                 }
  571.             }
  572.             if (Tree.SearchAuthor(authkey,&temp) &&
  573.                 strlen(authkey) == strlen(temp.key))
  574.             {
  575.                 ListRecord rec(&temp.data);
  576.                 int nitems = rec.ElementCount();
  577.                 int outitems = 0;
  578.                 if (nitems > numnewelements)
  579.                 {
  580.                     if (newelements != NULL)
  581.                             delete newelements;
  582.                         int numnewelements = (nitems+511) & ~(0x03ffL);
  583.                         newelements = new char*[numnewelements];
  584.                 }
  585.                 for (int i = 0; i < nitems; i++)
  586.                 {
  587.                     if (strcasecmp(rec[i],key) != 0)
  588.                     {
  589.                         newelements[outitems++] = rec[i];
  590.                     }
  591.                 }
  592.                 newelements[outitems++] = (char*) key;
  593.                 ListRecord newrec(outitems,newelements);
  594.                 Record rawrec = newrec;
  595.                 Tree.InsertAuthor(authkey,&rawrec);
  596.             } else if (authkey[0] != 0)
  597.             {
  598.                 if (1 > numnewelements)
  599.                 {
  600.                     if (newelements != NULL)
  601.                         delete newelements;
  602.                     int numnewelements = 512;
  603.                     newelements = new char*[numnewelements];
  604.                 }
  605.                 newelements[0] = (char*) key;
  606.                 ListRecord newrec(1,newelements);
  607.                 Record rawrec = newrec;
  608.                 Tree.InsertAuthor(authkey,&rawrec);
  609.             }
  610.         }
  611.         return TCL_OK;
  612.     } else if (strcmp(argv[1], "updatetitle") == 0)
  613.     {
  614.         Key key, titlekey, otitlekey;
  615.         if (_mode != ReadWrite)
  616.         {
  617.             Tcl_AppendResult(interp, "ReadOnly file!",(char *) NULL);
  618.             return TCL_ERROR;
  619.         }
  620.         if (argc != 5)
  621.         {
  622.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  623.                      argv[0]," ",argv[1],
  624.                      " newtitle oldtitle idkey\"",
  625.                      (char *) NULL);
  626.             return TCL_ERROR;
  627.         }
  628.         strncpy(titlekey,argv[2],KeySize-1);
  629.         titlekey[KeySize-1] = '\0';
  630.         strncpy(otitlekey,argv[3],KeySize-1);
  631.         otitlekey[KeySize-1] = '\0';
  632.         strncpy(key,argv[4],KeySize-1);
  633.         key[KeySize-1] = '\0';
  634.         if (strcasecmp(titlekey,otitlekey) != 0)
  635.         {
  636.             CoreItem temp;
  637.             if (Tree.SearchTitle(otitlekey,&temp) &&
  638.                 strlen(otitlekey) == strlen(temp.key))
  639.             {
  640.                 ListRecord rec(&temp.data);
  641.                 int nitems = rec.ElementCount();
  642.                 int outitems = 0;
  643.                 if (nitems > numnewelements)
  644.                 {
  645.                     if (newelements != NULL)
  646.                             delete newelements;
  647.                         int numnewelements = (nitems+511) & ~(0x03ffL);
  648.                         newelements = new char*[numnewelements];
  649.                 }
  650.                 for (int i = 0; i < nitems; i++)
  651.                 {
  652.                     if (strcasecmp(rec[i],key) != 0)
  653.                     {
  654.                         newelements[outitems++] = rec[i];
  655.                     }
  656.                 }
  657.                 if (outitems == 0)
  658.                 {
  659.                     Tree.DeleteTitle(otitlekey);
  660.                 } else
  661.                 {
  662.                     ListRecord newrec(outitems,newelements);
  663.                     Record rawrec = newrec;
  664.                     Tree.InsertTitle(otitlekey,&rawrec);
  665.                 }
  666.             }
  667.             if (Tree.SearchTitle(titlekey,&temp) &&
  668.                 strlen(titlekey) == strlen(temp.key))
  669.             {
  670.                 ListRecord rec(&temp.data);
  671.                 int nitems = rec.ElementCount();
  672.                 int outitems = 0;
  673.                 if (nitems > numnewelements)
  674.                 {
  675.                     if (newelements != NULL)
  676.                             delete newelements;
  677.                         int numnewelements = (nitems+511) & ~(0x03ffL);
  678.                         newelements = new char*[numnewelements];
  679.                 }
  680.                 for (int i = 0; i < nitems; i++)
  681.                 {
  682.                     if (strcasecmp(rec[i],key) != 0)
  683.                     {
  684.                         newelements[outitems++] = rec[i];
  685.                     }
  686.                 }
  687.                 newelements[outitems++] = (char*) key;
  688.                 ListRecord newrec(outitems,newelements);
  689.                 Record rawrec = newrec;
  690.                 Tree.InsertTitle(titlekey,&rawrec);
  691.             } else if (titlekey[0] != 0)
  692.             {
  693.                 if (1 > numnewelements)
  694.                 {
  695.                     if (newelements != NULL)
  696.                         delete newelements;
  697.                     int numnewelements = 512;
  698.                     newelements = new char*[numnewelements];
  699.                 }
  700.                 newelements[0] = (char*) key;
  701.                 ListRecord newrec(1,newelements);
  702.                 Record rawrec = newrec;
  703.                 Tree.InsertTitle(titlekey,&rawrec);
  704.             }
  705.         }
  706.         return TCL_OK;
  707.     } else if (strcmp(argv[1], "insertid") == 0)
  708.     {
  709.         Key key;
  710.         TkCardRecord *rec;
  711.         if (_mode != ReadWrite)
  712.         {
  713.             Tcl_AppendResult(interp, "ReadOnly file!",(char *) NULL);
  714.             return TCL_ERROR;
  715.         }
  716.         if (argc != 4)
  717.         {
  718.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  719.                      argv[0]," ",argv[1],
  720.                      " idkey cardhandle\"",
  721.                      (char *) NULL);
  722.             return TCL_ERROR;
  723.         }
  724.         strncpy(key,argv[2],KeySize-1);
  725.         key[KeySize-1] = '\0';
  726.         if (argv[3][0] == '\0')
  727.         {
  728.             Tcl_AppendResult(interp, "bad (empty) cardhandle", (char *) NULL);
  729.             return TCL_ERROR;
  730.         }
  731.         rec = FindCardByHandle(interp,argv[3]);
  732.         if (rec == NULL) return TCL_ERROR;
  733.         Record rawrec = *(rec->CardRec);
  734.         Tree.InsertId(key,&rawrec);
  735.         return TCL_OK;
  736.     } else if (strcmp(argv[1], "deleteid") == 0)
  737.     {
  738.         Key key;
  739.         if (_mode != ReadWrite)
  740.         {
  741.             Tcl_AppendResult(interp, "ReadOnly file!",(char *) NULL);
  742.             return TCL_ERROR;
  743.         }
  744.         if (argc != 3)
  745.         {
  746.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  747.                      argv[0]," ",argv[1],
  748.                      " idkey\"",
  749.                      (char *) NULL);
  750.             return TCL_ERROR;
  751.         }
  752.         strncpy(key,argv[2],KeySize-1);
  753.         key[KeySize-1] = '\0';
  754.         CoreItem temp;
  755.         if (Tree.SearchId(key,&temp) &&
  756.             strlen(key) == strlen(temp.key))
  757.         {
  758.             Tree.DeleteId(key);
  759.             return TCL_OK;
  760.         } else
  761.         {
  762.             Tcl_AppendResult(interp, "No such key: ",argv[2],(char *) NULL);
  763.             return TCL_ERROR;
  764.         }
  765.     } else if (strcmp(argv[1], "delete") == 0)
  766.     {
  767.         if (argc != 2)
  768.         {
  769.             Tcl_AppendResult(interp, "wrong # args: should be \"",
  770.                      argv[0]," ",argv[1],"\"",
  771.                      (char *) NULL);
  772.             return TCL_ERROR;
  773.         }
  774.         void_pt header = Tcl_HandleXlate (interp,Handles,argv[0]);
  775.         if (header == NULL) return TCL_ERROR;
  776.         Tcl_HandleFree (Handles,header);
  777.         return Tcl_DeleteCommand(interp,argv[0]);
  778.     } else
  779.     {
  780.         Tcl_AppendResult(interp, "Bad option: ",argv[1],(char *) NULL);
  781.         return TCL_ERROR;
  782.     }
  783. }
  784.  
  785.  
  786. static void deleteTkvBTree(ClientData clientData)
  787. {
  788.     register TkvBTree *tkvbtree = (TkvBTree *)clientData;
  789.     delete tkvbtree;
  790. }
  791.  
  792. static int tkvBTreeCommand(ClientData clientData, Tcl_Interp *interp,
  793.                int argc, char *argv[])
  794. {
  795.     register TkvBTree *tkvbtree = (TkvBTree *)clientData;
  796.     return tkvbtree->TclFunction(interp,argc,argv);
  797. }
  798.  
  799. static OpenMode ModeFromString(String m)
  800. {
  801.     if (m == "ReadWrite") return (ReadWrite);
  802.     else if (m == "ReadOnly") return (ReadOnly);
  803.     else if (m == "ReadWrite|Create") return((OpenMode)(ReadWrite|Create));
  804.     else if (m == "Create|ReadWrite") return((OpenMode)(ReadWrite|Create));
  805.     else return(ReadOnly);
  806. }
  807.  
  808. static int tkvBTreeCreate(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
  809. {
  810.     register TkvBTree *tkvbtree;
  811.     OpenMode mode;
  812.     int nfree;
  813.     if (argc < 2 || argc > 4)
  814.     {
  815.         Tcl_AppendResult(interp, "Wrong # args: should be \"",
  816.                  argv[0]," filename ?mode nfree?\"",
  817.                  (char*) NULL);
  818.         return TCL_ERROR;
  819.     }
  820.     switch (argc)
  821.     {
  822.         case 2: tkvbtree = new TkvBTree(argv[1]); break;
  823.         case 3: mode = ModeFromString(argv[2]);
  824.             tkvbtree = new TkvBTree(argv[1],mode);
  825.             break;
  826.         case 4: mode = ModeFromString(argv[2]);
  827.             if (Tcl_GetInt(interp,argv[3],&nfree) != TCL_OK) return(TCL_ERROR);
  828.             tkvbtree = new TkvBTree(argv[1],mode,nfree);
  829.             break;
  830.         default:
  831.         Tcl_AppendResult(interp, "Wrong # args: should be \"",
  832.                  argv[0]," filename ?mode nfree\"",
  833.                  (char*) NULL);
  834.         return TCL_ERROR;
  835.     }
  836.     char handle[32];
  837.     TkvBTree ** h = (TkvBTree **) Tcl_HandleAlloc (TkvBTree::Handles,handle);
  838.     *h = tkvbtree;
  839.     Tcl_CreateCommand(interp,handle,(Tcl_CmdProc*)tkvBTreeCommand,
  840.               (ClientData)tkvbtree,
  841.               (Tcl_CmdDeleteProc*)deleteTkvBTree);
  842.     Tcl_AppendResult(interp,handle,(char *) NULL);
  843.     return TCL_OK;
  844. }
  845.  
  846. int TkvBTree_Init(Tcl_Interp *interp)
  847. {
  848.     TkvBTree::Handles = Tcl_HandleTblInit("TkvBTree",sizeof(TkvBTree*),64);
  849.     Tcl_CreateCommand(interp, "TkvBTree", (Tcl_CmdProc*)tkvBTreeCreate,
  850.               (ClientData) NULL, (Tcl_CmdDeleteProc*) NULL);
  851.     return TCL_OK;
  852. }
  853.